# -*- coding: utf-8 -*-

from gurobipy import *

try:
    
    m = Model("Mip1")
    m.setParam('OutputFlag', 0)
    
    x = m.addVar(vtype=GRB.BINARY, name="x")
    y = m.addVar(vtype=GRB.BINARY, name="y")
    z = m.addVar(vtype=GRB.BINARY, name="z")
    
    m.setObjective(x + y + 2 * z, GRB.MAXIMIZE)
    
    m.addConstr(x +  2 * y + 3 * z <= 4, "c0")
    
    m.addConstr(x + y >= 1, "c1")
    
    m.optimize()
    
    for v in m.getVars():
        print(f"{v.VarName}: {v.X:g}")
        
    print(f"objval is {m.ObjVal:g}")

except GurobiError as e:
    print('Error code ' + str(e.errno) + ": " + str(e))

except AttributeError:
    print("Encountered an attribute error")
    
# from gurobipy import *

# # multidict 这个结构可以经过如下的赋值将键值分别拆开成三个gurobipy.tuplelist类型的变量
# # 其中categories就是一个列表的形式，minNutrition，maxNutrition将是两个字典，
# # 可以通过minNutrition[protein]获得 91
categories, minNutrition, maxNutrition = multidict({
    'calories': [1800, GRB.INFINITY],
    'protein': [91, GRB.INFINITY],
    'fat': [0, GRB.INFINITY],
    'sodium': [0, GRB.INFINITY]})
print(type(categories))

foods, cost = multidict({
    'hamburger': 2.56,
    'chicken': 1.99,
    'hotdog': 1.11})

nutritionValues = ({
    ('hamburger', 'calories'): 410,
    ('hamburger', 'protein'): 24,
    ('hamburger', 'fat'): 26,
    ('hamburger', 'sodium'): 730,
    ('chicken', 'calories'): 420,
    ('chicken', 'protein'): 32, 
    ('chicken', 'fat'): 10,
    ('chicken', 'sodium'): 1190,
    ('hotdog', 'calories'): 560,
    ('hotdog', 'protein'): 20,
    ('hotdog', 'fat'): 32,
    ('hotdog', 'sodium'): 1800})


m = Model("diet")

# 将'hamburger', 'chicken', 'hotdog'这三者分别作为优化变量
# 再强调一下，只能将这里buy视为一个新的变量，而不是某个数值，只是优化模型中待求解的变量
# 而且这个buy将成为一个gurobipy.tuplelist类型的变量，其key与foods的key一一对应
buy = m.addVars(foods, vtype=GRB.INTEGER, name="buy")

# 也可以写成
# buy = {}
# for f in foods:
#     buy[f] = m.addVar(name=f)

# m.setObjective(buy.prod(cost), GRB.MINIMIZE)
# 也可以写成
m.setObjective(sum(buy[f] * cost[f] for f in foods), GRB.MINIMIZE)

m.addConstrs(
    (quicksum(nutritionValues[f, c] * buy[f] for f in foods)
      == [minNutrition[c], maxNutrition[c]]
      for c in categories), "_")
# # 也可以写成
# # for c in categories:
# #     m.addRange(sum(nutritionValues[f, c] * buy[f]), minNutrition[c], maxNutrition[c])

def printSolution():
    if m.Status == GRB.Status.OPTIMAL:
        print(f"\nCost: {m.ObjVal:g}")
        print("\nBuy:")
        buyx = m.getAttr('x', buy)
        for f in foods:
            if buy[f].X > 0.0001:
                print(f"{f}, {buyx[f]}")
    else:
        print('No solution')
        
m.optimize()
printSolution()

